/**
 * @file tiny_mutex.c
 * @brief 互斥锁实现
 * @author 张恒宣
 * @LastEditTime 2024/9/22
 * @note 相对于二值信号量, 互斥锁的优先级继承机制可以防止优先级反转问题, 
 *        同时保存持有者信息, 可以防止其它线程释放互斥锁
 * 
 * MIT License
 *
 * Copyright (c) 2025 张恒宣 luckkeymail@163.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*********************
 *       头文件
 *********************/

#include "tiny_mutex.h"
#include "tiny_malloc.h"
#include "tiny_rtos_context.h"

/*********************
*      公共函数 
*********************/

/// @brief 创建互斥锁
/// @param  无需
/// @return 互斥锁实例, 如果失败返回tiny_null
tiny_mutex_t tiny_mutex_create(void)
{
    tiny_mutex_t mutex = tiny_malloc(sizeof(struct tiny_mutex));
    if (!mutex)
    {
        tiny_free(mutex);
        return tiny_null;
    }
    mutex->owner = tiny_null;
    tiny_init_list(&mutex->wait_list);
    return mutex;
}

/// @brief 释放互斥锁
/// @param mutex 待释放的互斥锁
void tiny_mutex_release(tiny_mutex_t mutex)
{
    if (!mutex)
    {
        return;
    }
    tiny_wakeup_all_list_thread(&mutex->wait_list);
    tiny_free(mutex);
}

/// @brief 上锁
/// @param mutex 待被上锁的互斥锁实例
/// @note: 如果互斥锁已经被当前线程持有, 则阻塞当前线程 不能在中断 定时器中使用
void tiny_mutex_lock(tiny_mutex_t mutex)
{
    if (!mutex || mutex->owner == get_self_thread())
    {
        return;
    }

    while (1)
    {
        int flag = disable_interrupt();

        if (!mutex->owner)
        {
            mutex->owner = get_self_thread();
            enable_interrupt(flag);
            return;
        }

        tiny_thread_t *self = get_self_thread();
        tiny_thread_t *owner = mutex->owner;

        if (self->cur_priority > owner->cur_priority)
        {
            tiny_thread_set_cur_priority(owner, self->cur_priority);
        }

        if (0 == tiny_suspend_thread_in_dst_list(get_self_thread(), &mutex->wait_list))
        {
            enable_interrupt(flag);
            return;
        }

        enable_interrupt(flag);
        schedule();
    }
}

/// @brief 解锁
/// @param mutex 待被解锁的互斥锁实例
/// @note 只有锁的拥有者才能解锁
void tiny_mutex_unlock(tiny_mutex_t mutex)
{
    if (!mutex || mutex->owner != get_self_thread())
    {
        return;
    }

    int flag = disable_interrupt();

    tiny_thread_resume_init_priority(mutex->owner);
    mutex->owner = tiny_null;
    tiny_wakeap_one_list_thread(&mutex->wait_list, tiny_true);
    enable_interrupt(flag);
}
